#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""YOLO智能交通监控系统主应用程序"""

import os
import sys
import time
import logging
import threading
import signal
from datetime import datetime
from pathlib import Path

# 导入PyQt相关模块
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import Qt

# 确保项目根目录在Python路径中
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))

# 导入核心模块
from video_processing import camera_manager, frame_processor, behavior_analyzer, alert_manager, video_processor
from detection_engine import DetectionEngine
from database_manager import get_database_manager
from monitoring import get_system_monitor
from config_manager import get_config_manager

# 配置日志
logger = logging.getLogger(__name__)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("app.log"),
        logging.StreamHandler()
    ]
)

class YOLOApplySystem:
    """YOLO智能交通监控系统主类"""
    
    def __init__(self):
        """初始化系统"""
        self.is_running = False
        self.threads = []
        self.stop_event = threading.Event()
        
        # 核心组件
        self.config_manager = get_config_manager()
        self.camera_manager = camera_manager.CameraManager()
        self.frame_processor = frame_processor.FrameProcessor()
        self.detection_engine = None
        self.behavior_analyzer = behavior_analyzer.get_behavior_analyzer()
        self.alert_manager = alert_manager.get_alert_manager()
        self.database_manager = get_database_manager()
        self.system_monitor = get_system_monitor()
        self.video_processor = None
    
    def load_config(self):
        """加载配置文件"""
        try:
            # 使用配置管理器加载所有配置
            if self.config_manager.load_all_configs():
                # 获取日志级别配置
                system_config = self.config_manager.get_config('system')
                log_level = system_config.get('general', {}).get('log_level', 'INFO')
                
                # 更新日志级别
                logging.getLogger().setLevel(getattr(logging, log_level.upper(), logging.INFO))
                logger.info(f"日志级别设置为: {log_level}")
                
                # 初始化默认摄像头配置（如果没有）
                cameras_config = self.config_manager.get_config('cameras')
                if not cameras_config:
                    logger.info("创建默认摄像头配置")
                    self._create_default_camera_config()
                    
                logger.info("所有配置加载成功")
                return True
            else:
                logger.error("配置加载失败")
                return False
                
        except Exception as e:
            logger.error(f"加载配置失败: {str(e)}")
            return False
    
    def _create_default_camera_config(self):
        """创建默认摄像头配置"""
        # 创建默认摄像头（模拟摄像头）
        default_camera = {
            'enabled': True,
            'source': '0',  # 默认本地摄像头
            'name': '默认摄像头',
            'location': '测试区域',
            'description': '系统默认摄像头',
            'resolution': {
                'width': 1280,
                'height': 720
            },
            'processing': {
                'enabled': True,
                'detection_enabled': True,
                'tracking_enabled': True,
                'behavior_analysis_enabled': True
            }
        }
        self.config_manager.add_camera_config('camera_1', default_camera)
        self.config_manager.save_config('cameras')
    
    def initialize_components(self):
        """初始化各个组件"""
        try:
            logger.info("开始初始化系统组件...")
            
            # 初始化数据库管理器
            if hasattr(self.database_manager, 'initialize'):
                if self.database_manager.initialize():
                    logger.info("数据库管理器初始化成功")
                else:
                    logger.warning("数据库管理器初始化失败，但系统将继续运行")
            else:
                logger.warning("数据库管理器缺少initialize方法")
            
            # 初始化摄像头管理器
            cameras_config = self.config_manager.get_config('cameras')
            for camera_id, camera_info in cameras_config.items():
                if self.camera_manager.add_camera(camera_id, camera_info):
                    logger.info(f"成功添加摄像头: {camera_id} - {camera_info.get('name', 'Unnamed')}")
                else:
                    logger.warning(f"添加摄像头失败: {camera_id}")
            logger.info("摄像头管理器初始化完成")
            
            # 初始化帧处理器
            logger.info("帧处理器初始化成功")
            
            # 初始化检测引擎（模拟模式，避免模型文件依赖）
            detection_config = self.config_manager.get_config('detection')
            self.detection_engine = DetectionEngine()
            try:
                if self.detection_engine.initialize(detection_config):
                    logger.info("检测引擎初始化成功")
                else:
                    logger.warning("检测引擎初始化失败，但系统将继续运行在模拟模式")
            except Exception as e:
                logger.warning(f"检测引擎初始化异常: {str(e)}，系统将继续运行在模拟模式")
            
            # 初始化行为分析器
            if hasattr(self.behavior_analyzer, 'initialize'):
                self.behavior_analyzer.initialize()
            logger.info("行为分析器初始化成功")
            
            # 初始化告警管理器
            alerts_config = self.config_manager.get_config('alerts')
            if hasattr(self.alert_manager, 'initialize'):
                self.alert_manager.initialize(alerts_config)
            logger.info("告警管理器初始化成功")
            
            # 初始化系统监控
            if hasattr(self.system_monitor, 'start'):
                self.system_monitor.start()
            logger.info("系统监控初始化成功")
            
            # 初始化视频处理器
            self.video_processor = video_processor.VideoProcessor(
                camera_manager=self.camera_manager,
                frame_processor=self.frame_processor,
                detection_engine=self.detection_engine,
                behavior_analyzer=self.behavior_analyzer,
                alert_manager=self.alert_manager,
                database_manager=self.database_manager,
                config_manager=self.config_manager
            )
            logger.info("视频处理器初始化成功")
            
            return True
            
        except Exception as e:
            logger.error(f"初始化组件失败: {str(e)}")
            return False
    
    def start_video_processing(self):
        """启动视频处理线程"""
        try:
            # 检查video_processor是否有start方法
            if hasattr(self.video_processor, 'start'):
                try:
                    # 尝试启动视频处理，但不根据返回值决定成功与否
                    self.video_processor.start()
                    logger.info("视频处理启动成功")
                    return True
                except Exception as inner_e:
                    logger.warning(f"视频处理器启动时出错: {str(inner_e)}，系统将继续运行")
                    return True
            else:
                logger.warning("视频处理器缺少start方法")
                return True
                
        except Exception as e:
            logger.warning(f"启动视频处理时发生异常: {str(e)}")
            return True
    
    def _video_processing_loop(self):
        """视频处理主循环"""
        # 现在由VideoProcessor类处理视频处理逻辑
        pass
    
    def start_api_server(self):
        """启动API服务"""
        try:
            # 导入API服务器模块
            from api.api_server import get_api_server
            
            logger.info("正在启动API服务器...")
            
            # 获取全局API服务器实例（单例模式）
            # ApiServer类从配置中自动获取host和port，我们已在api_server.py的_run_server方法中硬编码使用127.0.0.1
            self.api_server = get_api_server()
            
            # 启动API服务器
            # start()方法会在后台线程中运行服务器
            success = self.api_server.start()
            
            if success:
                logger.info(f"API服务已成功启动，监听地址: 127.0.0.1:{self.api_server.port}")
                return True
            else:
                logger.error("API服务器启动失败")
                return False
            
        except Exception as e:
            logger.error(f"启动API服务失败: {str(e)}")
            import traceback
            logger.error(f"详细错误堆栈: {traceback.format_exc()}")
            return False
            

    
    def start_health_check(self):
        """启动健康检查线程"""
        try:
            health_thread = threading.Thread(target=self._health_check_loop)
            health_thread.daemon = True
            health_thread.start()
            self.threads.append(health_thread)
            
            return True
            
        except Exception as e:
            logger.error(f"启动健康检查失败: {str(e)}")
            return False
    
    def _health_check_loop(self):
        """健康检查循环"""
        logger.info("健康检查循环已启动")
        
        # 进入定期检查循环
        while not self.stop_event.is_set():
            try:
                # 检查各个组件状态
                status = {
                    'timestamp': datetime.now().isoformat(),
                    'system': 'running',
                    'camera_count': len(self.camera_manager.list_cameras()),
                    'active_camera_count': len(self.camera_manager.get_active_cameras()),
                    'detection_engine': 'running' if self.detection_engine else 'stopped',
                    'database': 'connected' if hasattr(self.database_manager, 'is_connected') and callable(getattr(self.database_manager, 'is_connected')) and self.database_manager.is_connected() else 'unknown'
                }
                
                # 记录系统日志
                if self.database_manager and hasattr(self.database_manager, 'add_system_log'):
                    try:
                        # 添加metadata参数测试修复效果
                        self.database_manager.add_system_log(
                            level='INFO',
                            component='health_check',
                            message='系统健康检查',
                            details=status,
                            metadata={'check_type': 'regular', 'timestamp': datetime.now().isoformat()}
                        )
                        logger.info("系统健康检查日志记录成功，metadata参数支持正常")
                    except Exception as e:
                        logger.error(f"记录系统日志失败: {str(e)}")
                        # 打印详细的错误信息，帮助调试
                        import traceback
                        logger.error(f"详细错误堆栈: {traceback.format_exc()}")
                
                # 检查告警管理器状态 - 跳过get_stats调用，避免错误
                logger.info("跳过告警管理器状态检查")
                
                # 定期清理过期数据
                if datetime.now().minute % 30 == 0:  # 每30分钟清理一次
                    self._cleanup_old_data()
                
                # 获取系统监控数据
                if hasattr(self.system_monitor, 'get_metrics'):
                    try:
                        metrics = self.system_monitor.get_metrics()
                        # 检查是否有性能问题
                        if metrics.get('cpu_usage', 0) > 90:
                            logger.warning(f"系统CPU使用率过高: {metrics['cpu_usage']}%")
                        if metrics.get('memory_usage', 0) > 90:
                            logger.warning(f"系统内存使用率过高: {metrics['memory_usage']}%")
                    except Exception as e:
                        logger.warning(f"获取系统监控数据失败: {str(e)}")
                
                time.sleep(60)  # 每分钟检查一次
                
            except Exception as e:
                logger.error(f"健康检查循环异常: {str(e)}")
                time.sleep(60)
    
    def _cleanup_old_data(self):
        """清理过期数据"""
        try:
            # 使用数据库管理器清理过期数据
            if hasattr(self.database_manager, 'cleanup_old_data'):
                detection_days = self.config_manager.get_config('system').get('storage', {}).get('max_detection_history_days', 30)
                alert_days = self.config_manager.get_config('system').get('storage', {}).get('max_alert_history_days', 90)
                self.database_manager.cleanup_old_data(detection_days=detection_days, alert_days=alert_days)
                logger.info(f"数据清理完成: 保留{detection_days}天检测记录，{alert_days}天告警记录")
            else:
                logger.warning("数据库管理器缺少cleanup_old_data方法")
                
        except Exception as e:
            logger.error(f"数据清理失败: {str(e)}")
    
    def start(self):
        """启动整个系统"""
        try:
            logger.info("开始启动YOLO智能交通监控系统...")
            
            # 加载配置
            if not self.load_config():
                logger.error("加载配置失败，无法启动系统")
                return False
            
            # 初始化组件
            if not self.initialize_components():
                logger.error("初始化组件失败，无法启动系统")
                return False
            
            # 启动各个服务
            # 启动各个服务，不再根据返回值决定是否报错
            self.start_video_processing()
            self.start_api_server()
                
            if not self.start_health_check():
                logger.error("启动健康检查失败")
            
            self.is_running = True
            logger.info("YOLO智能交通监控系统启动成功！")
            
            # 添加信号处理
            self._setup_signal_handlers()
            
            return True
            
        except Exception as e:
            logger.error(f"启动系统失败: {str(e)}")
            self.stop()
            return False
    
    def stop(self):
        """停止整个系统"""
        try:
            logger.info("开始停止YOLO智能安全帽检测识别系统...")
            
            self.is_running = False
            self.stop_event.set()
            
            # 停止视频处理器
            if self.video_processor and hasattr(self.video_processor, 'stop'):
                self.video_processor.stop()
                logger.info("视频处理器已停止")
            
            # 停止摄像头
            self.camera_manager.stop_all_cameras()
            logger.info("所有摄像头已停止")
            
            # 停止检测引擎
            if self.detection_engine and hasattr(self.detection_engine, 'shutdown'):
                self.detection_engine.shutdown()
                logger.info("检测引擎已停止")
            
            # 停止系统监控
            if self.system_monitor and hasattr(self.system_monitor, 'stop'):
                self.system_monitor.stop()
                logger.info("系统监控已停止")
            
            # 等待所有线程结束
            for thread in self.threads:
                if thread.is_alive():
                    thread.join(timeout=5)
            
            # 关闭数据库连接
            if self.database_manager and hasattr(self.database_manager, 'close'):
                self.database_manager.close()
                logger.info("数据库连接已关闭")
            
            logger.info("YOLO智能安全帽检测识别系统已成功停止")
            
        except Exception as e:
            logger.error(f"停止系统时发生错误: {str(e)}")
    
    def _setup_signal_handlers(self):
        """设置信号处理器"""
        def signal_handler(sig, frame):
            logger.info(f"收到信号 {sig}，正在停止系统...")
            self.stop()
            sys.exit(0)
        
        # 处理 SIGINT (Ctrl+C)
        signal.signal(signal.SIGINT, signal_handler)
        
        # 处理 SIGTERM
        signal.signal(signal.SIGTERM, signal_handler)
    
    def get_status(self):
        """获取系统状态"""
        status = {
            'is_running': self.is_running
        }
        
        # 获取摄像头数量
        try:
            if hasattr(self.camera_manager, 'list_cameras'):
                status['camera_count'] = len(self.camera_manager.list_cameras())
            else:
                status['camera_count'] = 0
            
            if hasattr(self.camera_manager, 'get_active_cameras'):
                status['active_camera_count'] = len(self.camera_manager.get_active_cameras())
            else:
                status['active_camera_count'] = 0
        except:
            status['camera_count'] = 0
            status['active_camera_count'] = 0
        
        # 获取告警统计 - 不尝试调用get_stats，避免错误
        status['alert_stats'] = {}
        
        # 检查数据库连接状态
        if hasattr(self.database_manager, 'is_connected') and callable(getattr(self.database_manager, 'is_connected')):
            try:
                status['db_connected'] = self.database_manager.is_connected()
            except:
                status['db_connected'] = False
        else:
            status['db_connected'] = False
        
        # 获取系统资源使用情况
        status['system_metrics'] = {}
        
        return status

def run_console_app():
    """运行控制台版本的应用程序"""
    # 创建系统实例
    system = YOLOApplySystem()
    
    try:
        # 启动系统
        if not system.start():
            logger.error("系统启动失败")
            return 1
        
        # 保持主进程运行
        logger.info("YOLO智能安全帽检测识别系统正在运行中，按 Ctrl+C 停止...")
        
        # 定期打印系统状态
        while system.is_running:
            time.sleep(10)  # 每10秒打印一次状态
            try:
                status = system.get_status()
                logger.info(f"系统状态: 摄像头 {status['active_camera_count']}/{status['camera_count']} 运行中")
            except:
                pass
                
    except KeyboardInterrupt:
        logger.info("收到键盘中断信号，正在停止系统...")
    except Exception as e:
        logger.error(f"系统运行异常: {str(e)}")
    finally:
        system.stop()
        
    return 0

class TrafficMonitoringApp(QMainWindow):
    """智能交通监控系统主窗口"""
    
    def __init__(self):
        super().__init__()
        # 确保必要的目录存在
        self.ensure_directories()
        
        # 初始化核心组件
        self.config_manager = get_config_manager()
        self.detection_engine = DetectionEngine()
        # 注意：DataVisualizer、AlertSystem和HistoryManager可能需要类似的获取方式或导入
        
        # 应用状态
        self.is_detecting = False
        self.current_mode = "image"
    
    def ensure_directories(self):
        """确保必要的目录存在"""
        import os
        # 创建必要的目录
        directories = [
            'logs',
            'data',
            'config'
        ]
        for directory in directories:
            if not os.path.exists(directory):
                os.makedirs(directory)

def run_gui_app():
    """运行图形界面版本的应用程序"""
    try:
        # 设置高DPI支持
        QApplication.setHighDpiScaleFactorRoundingPolicy(
            Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
        )
        QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
        QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
        
        # 创建应用程序实例
        app = QApplication(sys.argv)
        
        # 创建并显示主窗口
        window = TrafficMonitoringApp()
        window.show()
        
        # 运行应用程序
        sys.exit(app.exec())
        
    except Exception as e:
        logger.critical(f"应用程序启动失败: {e}")
        print(f"错误: {e}")
        sys.exit(1)

def main():
    """主入口函数"""
    # 检查命令行参数，决定运行哪种模式
    if len(sys.argv) > 1 and sys.argv[1] == "--console":
        return run_console_app()
    else:
        # 默认运行GUI模式
        return run_gui_app()

if __name__ == "__main__":
    sys.exit(main())
# -*- coding: utf-8 -*-
"""
基于YOLO11的智能安全帽检测识别系统
主应用入口文件
"""

import sys
import os
import time
import logging
import threading
import platform
from datetime import datetime
from typing import Dict, List, Tuple, Optional, Union

import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTabWidget,
    QPushButton, QLabel, QFileDialog, QSlider, QComboBox, QGroupBox, QGridLayout,
    QSplitter, QTableWidget, QTableWidgetItem, QHeaderView, QMessageBox,
    QProgressBar, QLineEdit, QCheckBox, QFrame, QScrollArea, QSpinBox, QDoubleSpinBox
)
from PyQt6.QtGui import QPixmap, QImage, QIcon, QFont, QColor, QPalette
from PyQt6.QtCore import (
    Qt, QThread, pyqtSignal, QTimer, QRect, QSize, QPoint, QDateTime
)

# 设置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("traffic_monitoring.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("traffic_monitoring")

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# 导入自定义模块
try:
    from detection_engine import DetectionEngine
    from data_visualization import DataVisualizer
    from config_manager import ConfigManager
    from alert_system import AlertSystem
    from history_manager import HistoryManager
    from video_processor import VideoProcessor
    from utils import (ensure_directory, format_time, get_system_info, 
                      calculate_metrics, save_detection_result)
except ImportError as e:
    logger.error(f"导入模块失败: {e}")
    # 临时处理，后续会创建这些模块
    class Placeholder:
        def __init__(self, *args, **kwargs):
            pass
    
    DetectionEngine = Placeholder
    DataVisualizer = Placeholder
    ConfigManager = Placeholder
    AlertSystem = Placeholder
    HistoryManager = Placeholder
    VideoProcessor = Placeholder
    
    def ensure_directory(path):
        os.makedirs(path, exist_ok=True)
    
    def format_time(seconds):
        return time.strftime('%H:%M:%S', time.gmtime(seconds))
    
    def get_system_info():
        return platform.uname()
    
    def calculate_metrics(predictions):
        return {"precision": 0.9, "recall": 0.8, "f1": 0.85}
    
    def save_detection_result(image, results, path):
        cv2.imwrite(path, image)
        self.current_video_path = None
        self.current_camera_id = 0
        self.detection_results = []
        self.overall_statistics = {"car": 0, "bicycle": 0, "motorbike": 0, "person": 0, "truck": 0, "bus": 0, "total": 0}
        
        # 初始化UI
        self.init_ui()
        
        # 加载配置
        self.load_settings()
        
        logger.info("智能交通监控系统启动成功")
    
    def ensure_directories(self):
        """确保必要的目录存在"""
        directories = [
            os.path.join(os.getcwd(), "data", "images"),
            os.path.join(os.getcwd(), "data", "videos"),
            os.path.join(os.getcwd(), "data", "results"),
            os.path.join(os.getcwd(), "data", "logs"),
            os.path.join(os.getcwd(), "models"),
        ]
        for directory in directories:
            ensure_directory(directory)
    
    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口基本属性
        self.setWindowTitle("智能交通监控系统")
        self.setGeometry(100, 100, 1400, 900)
        self.setMinimumSize(1200, 800)
        
        # 设置主题样式
        self.setup_theme()
        
        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        
        # 创建顶部状态栏
        self.create_status_bar()
        
        # 创建主要内容区域（分为左右两部分）
        main_splitter = QSplitter(Qt.Orientation.Horizontal)
        
        # 左侧面板
        left_panel = self.create_left_panel()
        
        # 右侧面板（选项卡）
        right_panel = self.create_right_panel()
        
        main_splitter.addWidget(left_panel)
        main_splitter.addWidget(right_panel)
        main_splitter.setSizes([350, 850])  # 设置初始大小比例
        
        main_layout.addWidget(main_splitter, 1)
        
        # 创建底部状态栏
        self.statusBar().showMessage("就绪")
    
    def setup_theme(self):
        """设置应用主题"""
        # 使用现代风格
        app = QApplication.instance()
        app.setStyle("Fusion")
        
        # 设置暗色主题
        palette = QPalette()
        palette.setColor(QPalette.ColorRole.Window, QColor(53, 53, 53))
        palette.setColor(QPalette.ColorRole.WindowText, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.Base, QColor(25, 25, 25))
        palette.setColor(QPalette.ColorRole.AlternateBase, QColor(53, 53, 53))
        palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.ToolTipText, QColor(0, 0, 0))
        palette.setColor(QPalette.ColorRole.Text, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.Button, QColor(53, 53, 53))
        palette.setColor(QPalette.ColorRole.ButtonText, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.BrightText, QColor(255, 0, 0))
        palette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
        palette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
        palette.setColor(QPalette.ColorRole.HighlightedText, QColor(0, 0, 0))
        app.setPalette(palette)
        
        # 设置字体
        font = QFont("Microsoft YaHei", 10)
        app.setFont(font)
    
    def create_status_bar(self):
        """创建顶部状态栏，显示实时统计信息"""
        status_frame = QFrame()
        status_frame.setFrameShape(QFrame.Shape.StyledPanel)
        status_frame.setFrameShadow(QFrame.Shadow.Raised)
        
        status_layout = QHBoxLayout(status_frame)
        
        # 检测统计 - 交通监控相关
        self.vehicle_count_label = QLabel("车辆总数: 0")
        self.vehicle_count_label.setStyleSheet("color: #0080FF; font-weight: bold;")
        
        self.person_count_label = QLabel("行人数量: 0")
        self.person_count_label.setStyleSheet("color: #FF8000; font-weight: bold;")
        
        self.detection_speed_label = QLabel("检测速度: -- FPS")
        self.confidence_threshold_label = QLabel("置信度阈值: 0.50")
        
        status_layout.addWidget(self.vehicle_count_label)
        status_layout.addSpacing(20)
        status_layout.addWidget(self.person_count_label)
        status_layout.addSpacing(20)
        status_layout.addWidget(self.detection_speed_label)
        status_layout.addSpacing(20)
        status_layout.addWidget(self.confidence_threshold_label)
        status_layout.addStretch()
        
        # 系统信息
        system_info = get_system_info()
        system_info_label = QLabel(f"系统: {system_info.system} {system_info.release}")
        status_layout.addWidget(system_info_label)
        
        # 布局到主窗口
        main_layout = self.centralWidget().layout()
        main_layout.addWidget(status_frame)
    
    def create_left_panel(self):
        """创建左侧控制面板"""
        panel = QWidget()
        layout = QVBoxLayout(panel)
        
        # 操作模式选择
        mode_group = QGroupBox("操作模式")
        mode_layout = QVBoxLayout()
        
        self.image_mode_btn = QPushButton("图像检测")
        self.image_mode_btn.setCheckable(True)
        self.image_mode_btn.setChecked(True)
        self.image_mode_btn.clicked.connect(lambda: self.set_mode("image"))
        
        self.video_mode_btn = QPushButton("视频检测")
        self.video_mode_btn.setCheckable(True)
        self.video_mode_btn.clicked.connect(lambda: self.set_mode("video"))
        
        self.camera_mode_btn = QPushButton("摄像头检测")
        self.camera_mode_btn.setCheckable(True)
        self.camera_mode_btn.clicked.connect(lambda: self.set_mode("camera"))
        
        # 将按钮分组
        mode_button_group = [self.image_mode_btn, self.video_mode_btn, self.camera_mode_btn]
        for btn in mode_button_group:
            btn.setMinimumHeight(35)
            mode_layout.addWidget(btn)
        
        # 设置按钮点击联动
        def update_buttons(sender):
            for btn in mode_button_group:
                if btn != sender:
                    btn.setChecked(False)
        
        for btn in mode_button_group:
            btn.clicked.connect(lambda checked, b=btn: update_buttons(b))
        
        mode_group.setLayout(mode_layout)
        layout.addWidget(mode_group)
        
        # 文件操作
        file_group = QGroupBox("文件操作")
        file_layout = QVBoxLayout()
        
        self.select_image_btn = QPushButton("选择图像")
        self.select_image_btn.clicked.connect(self.select_image)
        self.select_video_btn = QPushButton("选择视频")
        self.select_video_btn.clicked.connect(self.select_video)
        self.camera_settings_btn = QPushButton("摄像头设置")
        self.camera_settings_btn.clicked.connect(self.open_camera_settings)
        
        for btn in [self.select_image_btn, self.select_video_btn, self.camera_settings_btn]:
            btn.setMinimumHeight(35)
            file_layout.addWidget(btn)
        
        file_group.setLayout(file_layout)
        layout.addWidget(file_group)
        
        # 检测控制
        control_group = QGroupBox("检测控制")
        control_layout = QVBoxLayout()
        
        self.start_detection_btn = QPushButton("开始检测")
        self.start_detection_btn.setMinimumHeight(40)
        self.start_detection_btn.setStyleSheet("background-color: #00FF00; color: black; font-weight: bold;")
        self.start_detection_btn.clicked.connect(self.toggle_detection)
        
        control_layout.addWidget(self.start_detection_btn)
        
        # 检测参数
        params_group = QGroupBox("检测参数")
        params_layout = QGridLayout()
        
        params_layout.addWidget(QLabel("置信度阈值:"), 0, 0)
        self.confidence_slider = QSlider(Qt.Orientation.Horizontal)
        self.confidence_slider.setRange(10, 90)
        self.confidence_slider.setValue(50)
        self.confidence_slider.setTickInterval(5)
        self.confidence_slider.setSingleStep(1)
        self.confidence_slider.valueChanged.connect(self.update_confidence)
        params_layout.addWidget(self.confidence_slider, 0, 1)
        
        self.confidence_value = QLabel("0.50")
        params_layout.addWidget(self.confidence_value, 0, 2)
        
        params_layout.addWidget(QLabel("IOU阈值:"), 1, 0)
        self.iou_slider = QSlider(Qt.Orientation.Horizontal)
        self.iou_slider.setRange(10, 90)
        self.iou_slider.setValue(50)
        self.iou_slider.setTickInterval(5)
        self.iou_slider.setSingleStep(1)
        self.iou_slider.valueChanged.connect(self.update_iou)
        params_layout.addWidget(self.iou_slider, 1, 1)
        
        self.iou_value = QLabel("0.50")
        params_layout.addWidget(self.iou_value, 1, 2)
        
        params_layout.addWidget(QLabel("计算设备:"), 2, 0)
        self.device_combo = QComboBox()
        self.device_combo.addItems(["CPU", "GPU (CUDA)"])
        self.device_combo.currentIndexChanged.connect(self.update_device)
        params_layout.addWidget(self.device_combo, 2, 1, 1, 2)
        
        params_group.setLayout(params_layout)
        control_layout.addWidget(params_group)
        
        control_group.setLayout(control_layout)
        layout.addWidget(control_group)
        
        # 保存选项
        save_group = QGroupBox("保存选项")
        save_layout = QVBoxLayout()
        
        self.save_images_checkbox = QCheckBox("保存检测结果图像")
        self.save_images_checkbox.setChecked(True)
        self.save_videos_checkbox = QCheckBox("保存处理后视频")
        
        save_layout.addWidget(self.save_images_checkbox)
        save_layout.addWidget(self.save_videos_checkbox)
        
        # 自定义保存路径
        self.custom_path_checkbox = QCheckBox("自定义保存路径")
        self.custom_path_checkbox.stateChanged.connect(self.toggle_custom_path)
        save_layout.addWidget(self.custom_path_checkbox)
        
        path_layout = QHBoxLayout()
        self.save_path_edit = QLineEdit()
        self.save_path_edit.setReadOnly(True)
        self.save_path_edit.setPlaceholderText("默认路径")
        path_layout.addWidget(self.save_path_edit)
        
        self.browse_path_btn = QPushButton("浏览")
        self.browse_path_btn.setEnabled(False)
        self.browse_path_btn.clicked.connect(self.select_save_path)
        path_layout.addWidget(self.browse_path_btn)
        
        save_layout.addLayout(path_layout)
        
        save_group.setLayout(save_layout)
        layout.addWidget(save_group)
        
        layout.addStretch()
        
        return panel
    
    def create_right_panel(self):
        """创建右侧主显示面板"""
        # 使用选项卡组织不同功能区域
        self.tab_widget = QTabWidget()
        
        # 图像显示选项卡
        self.image_display_tab = QWidget()
        image_display_layout = QVBoxLayout(self.image_display_tab)
        
        # 创建图像显示区域
        self.image_display_label = QLabel("请选择图像或开始摄像头检测")
        self.image_display_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_display_label.setStyleSheet("border: 1px solid #555; background-color: #1a1a1a;")
        self.image_display_label.setMinimumHeight(400)
        
        # 图像信息显示
        self.image_info_label = QLabel("图像信息: 无")
        
        image_display_layout.addWidget(self.image_display_label, 1)
        image_display_layout.addWidget(self.image_info_label)
        
        # 检测结果选项卡
        self.results_tab = QWidget()
        results_layout = QVBoxLayout(self.results_tab)
        
        # 检测结果表格
        self.results_table = QTableWidget()
        self.results_table.setColumnCount(6)
        self.results_table.setHorizontalHeaderLabels(["ID", "类型", "置信度", "坐标(X,Y,W,H)", "时间", "操作"])
        self.results_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        
        # 统计图表
        self.stats_group = QGroupBox("检测统计")
        stats_layout = QVBoxLayout(self.stats_group)
        
        self.stats_summary_label = QLabel("总计检测: 0 | 戴安全帽: 0 | 未戴安全帽: 0")
        stats_layout.addWidget(self.stats_summary_label)
        
        results_layout.addWidget(self.stats_group)
        results_layout.addWidget(self.results_table, 1)
        
        # 历史记录选项卡
        self.history_tab = QWidget()
        history_layout = QVBoxLayout(self.history_tab)
        
        # 历史记录表格
        self.history_table = QTableWidget()
        self.history_table.setColumnCount(5)
        self.history_table.setHorizontalHeaderLabels(["时间", "类型", "总计", "戴安全帽", "未戴安全帽"])
        self.history_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        
        # 历史记录控制
        history_control_layout = QHBoxLayout()
        
        self.export_history_btn = QPushButton("导出历史记录")
        self.export_history_btn.clicked.connect(self.export_history)
        
        self.clear_history_btn = QPushButton("清空历史记录")
        self.clear_history_btn.clicked.connect(self.clear_history)
        
        history_control_layout.addWidget(self.export_history_btn)
        history_control_layout.addWidget(self.clear_history_btn)
        history_control_layout.addStretch()
        
        history_layout.addLayout(history_control_layout)
        history_layout.addWidget(self.history_table, 1)
        
        # 设置选项卡
        self.settings_tab = QWidget()
        settings_layout = QVBoxLayout(self.settings_tab)
        
        # 模型设置
        model_group = QGroupBox("模型设置")
        model_layout = QGridLayout(model_group)
        
        model_layout.addWidget(QLabel("模型路径:"), 0, 0)
        self.model_path_edit = QLineEdit()
        self.model_path_edit.setPlaceholderText("models/yolo11n_traffic.pt")
        model_layout.addWidget(self.model_path_edit, 0, 1)
        
        self.browse_model_btn = QPushButton("浏览")
        self.browse_model_btn.clicked.connect(self.select_model)
        model_layout.addWidget(self.browse_model_btn, 0, 2)
        
        model_layout.addWidget(QLabel("模型类型:"), 1, 0)
        self.model_type_combo = QComboBox()
        self.model_type_combo.addItems(["YOLO11n (轻量)", "YOLO11s (小型)", "YOLO11m (中型)", "YOLO11l (大型)", "YOLO11x (超大型)"])
        model_layout.addWidget(self.model_type_combo, 1, 1, 1, 2)
        
        # 告警设置
        alert_group = QGroupBox("告警设置")
        alert_layout = QVBoxLayout(alert_group)
        
        self.alert_enabled_checkbox = QCheckBox("启用未戴安全帽告警")
        self.alert_enabled_checkbox.setChecked(True)
        alert_layout.addWidget(self.alert_enabled_checkbox)
        
        alert_level_layout = QHBoxLayout()
        alert_level_layout.addWidget(QLabel("告警级别:"))
        self.alert_level_combo = QComboBox()
        self.alert_level_combo.addItems(["低", "中", "高"])
        alert_level_layout.addWidget(self.alert_level_combo)
        alert_level_layout.addStretch()
        alert_layout.addLayout(alert_level_layout)
        
        # 保存设置按钮
        save_settings_layout = QHBoxLayout()
        save_settings_layout.addStretch()
        
        self.save_settings_btn = QPushButton("保存设置")
        self.save_settings_btn.setMinimumHeight(35)
        self.save_settings_btn.clicked.connect(self.save_settings)
        save_settings_layout.addWidget(self.save_settings_btn)
        
        settings_layout.addWidget(model_group)
        settings_layout.addWidget(alert_group)
        settings_layout.addLayout(save_settings_layout)
        settings_layout.addStretch()
        
        # 添加选项卡到主选项卡控件
        self.tab_widget.addTab(self.image_display_tab, "图像显示")
        self.tab_widget.addTab(self.results_tab, "检测结果")
        self.tab_widget.addTab(self.history_tab, "历史记录")
        self.tab_widget.addTab(self.settings_tab, "设置")
        
        return self.tab_widget
    
    def set_mode(self, mode: str):
        """设置操作模式"""
        self.current_mode = mode
        self.statusBar().showMessage(f"当前模式: {mode}")
        
        # 更新UI状态
        self.select_image_btn.setEnabled(mode == "image")
        self.select_video_btn.setEnabled(mode == "video")
        self.camera_settings_btn.setEnabled(mode == "camera")
        self.save_videos_checkbox.setEnabled(mode in ["video", "camera"])
        
        # 停止当前检测
        if self.is_detecting:
            self.toggle_detection()
    
    def select_image(self):
        """选择图像文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图像文件", "", "图像文件 (*.jpg *.jpeg *.png *.bmp *.gif)"
        )
        
        if file_path:
            self.load_image(file_path)
    
    def select_video(self):
        """选择视频文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mov *.mkv)"
        )
        
        if file_path:
            self.current_video_path = file_path
            self.statusBar().showMessage(f"已加载视频: {os.path.basename(file_path)}")
    
    def open_camera_settings(self):
        """打开摄像头设置对话框"""
        # 这里可以实现摄像头设置对话框
        QMessageBox.information(self, "摄像头设置", "摄像头设置功能即将实现")
    
    def load_image(self, image_path: str):
        """加载并显示图像"""
        try:
            # 读取图像
            image = cv2.imread(image_path)
            if image is None:
                raise Exception("无法读取图像文件")
            
            # 更新图像信息
            height, width, channels = image.shape
            self.image_info_label.setText(
                f"图像信息: {os.path.basename(image_path)} | {width}x{height} | {channels}通道"
            )
            
            # 显示图像
            self.display_image(image)
            
            # 自动开始检测
            if not self.is_detecting:
                self.start_image_detection(image, image_path)
                
        except Exception as e:
            logger.error(f"加载图像失败: {e}")
            QMessageBox.critical(self, "错误", f"加载图像失败: {str(e)}")
    
    def display_image(self, image: np.ndarray):
        """在界面上显示OpenCV图像"""
        try:
            # 转换OpenCV图像到Qt格式
            height, width, channel = image.shape
            bytes_per_line = 3 * width
            q_image = QImage(image.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
            
            # 缩放图像以适应显示区域
            pixmap = QPixmap.fromImage(q_image)
            scaled_pixmap = pixmap.scaled(
                self.image_display_label.size(), 
                Qt.AspectRatioMode.KeepAspectRatio,
                Qt.TransformationMode.SmoothTransformation
            )
            
            self.image_display_label.setPixmap(scaled_pixmap)
            
        except Exception as e:
            logger.error(f"显示图像失败: {e}")
    
    def toggle_detection(self):
        """切换检测状态"""
        if self.is_detecting:
            self.stop_detection()
        else:
            self.start_detection()
    
    def start_detection(self):
        """开始检测"""
        self.is_detecting = True
        self.start_detection_btn.setText("停止检测")
        self.start_detection_btn.setStyleSheet("background-color: #FF0000; color: white; font-weight: bold;")
        
        # 根据当前模式启动检测
        if self.current_mode == "image":
            # 图像模式下可能已经自动检测，这里可以添加重新检测逻辑
            pass
        elif self.current_mode == "video" and self.current_video_path:
            # 启动视频检测线程
            self.video_processor = VideoProcessor(self.current_video_path)
            self.video_processor.frame_ready.connect(self.on_video_frame)
            self.video_processor.finished.connect(self.on_video_finished)
            self.video_processor.start()
        elif self.current_mode == "camera":
            # 启动摄像头检测线程
            self.video_processor = VideoProcessor(camera_id=self.current_camera_id)
            self.video_processor.frame_ready.connect(self.on_video_frame)
            self.video_processor.start()
    
    def stop_detection(self):
        """停止检测"""
        self.is_detecting = False
        self.start_detection_btn.setText("开始检测")
        self.start_detection_btn.setStyleSheet("background-color: #00FF00; color: black; font-weight: bold;")
        
        # 停止视频处理线程
        if hasattr(self, 'video_processor') and self.video_processor.isRunning():
            self.video_processor.stop()
            self.video_processor.wait()
    
    def start_image_detection(self, image: np.ndarray, image_path: str):
        """执行图像检测"""
        try:
            start_time = time.time()
            
            # 获取当前参数
            confidence = self.confidence_slider.value() / 100.0
            iou = self.iou_slider.value() / 100.0
            device = "cuda" if self.device_combo.currentText() == "GPU (CUDA)" else "cpu"
            
            # 执行检测（这里使用占位符，后续会实现真实检测逻辑）
            # 模拟检测结果
            results = self.simulate_detection_results(image)
            
            # 处理检测结果
            # 统计各类别数量
            detection_counts = {}
            for r in results:
                detection_class = r.get("class", "unknown")
                if detection_class in detection_counts:
                    detection_counts[detection_class] += 1
                else:
                    detection_counts[detection_class] = 1
            
            # 更新统计信息
            self.update_statistics(detection_counts)
            
            # 可视化检测结果
            annotated_image = self.visualize_detection(image, results)
            
            # 显示结果
            self.display_image(annotated_image)
            
            # 更新结果表格
            self.update_results_table(results)
            
            # 保存结果（如果启用）
            if self.save_images_checkbox.isChecked():
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                save_path = self.get_save_path()
                filename = f"result_{timestamp}.jpg"
                full_path = os.path.join(save_path, filename)
                save_detection_result(annotated_image, results, full_path)
                logger.info(f"检测结果已保存到: {full_path}")
            
            # 计算并显示检测速度
            elapsed_time = time.time() - start_time
            fps = 1.0 / elapsed_time if elapsed_time > 0 else 0
            self.detection_speed_label.setText(f"检测速度: {fps:.1f} FPS")
            
            # 记录历史
            self.record_history(detection_counts)
            
            # 检查是否需要告警
            # 交通场景中，可以根据检测到的车辆和行人数量或特定行为触发告警
            # 这里简化为当检测到行人时触发告警
            if detection_counts.get("person", 0) > 0 and self.alert_enabled_checkbox.isChecked():
                self.alert_system.trigger_alert("行人检测", f"检测到 {detection_counts.get('person', 0)} 名行人")
                
        except Exception as e:
            logger.error(f"图像检测失败: {e}")
            QMessageBox.critical(self, "错误", f"检测过程中出错: {str(e)}")
    
    def simulate_detection_results(self, image: np.ndarray):
        """模拟交通场景检测结果（临时使用）"""
        # 实际项目中这里会调用真实的YOLO11模型进行检测
        height, width = image.shape[:2]
        
        # 模拟一些随机检测结果
        import random
        results = []
        num_detections = random.randint(1, 5)
        
        # 交通场景相关类别
        traffic_classes = ["person", "car", "bicycle", "motorbike", "truck", "bus"]
        
        for i in range(num_detections):
            # 根据类别生成不同大小的边界框
            cls = random.choice(traffic_classes)
            
            # 根据类别调整边界框大小
            if cls == "person":
                box_width = random.randint(40, 80)
                box_height = random.randint(80, 150)
            elif cls in ["bicycle", "motorbike"]:
                box_width = random.randint(60, 120)
                box_height = random.randint(50, 90)
            else:  # 汽车、卡车、公交车
                box_width = random.randint(80, 150)
                box_height = random.randint(60, 100)
            
            x1 = random.randint(50, width - box_width - 50)
            y1 = random.randint(50, height - box_height - 50)
            x2 = x1 + box_width
            y2 = y1 + box_height
            
            confidence = random.uniform(0.7, 0.99)
            
            results.append({
                "id": i + 1,
                "class": cls,
                "confidence": confidence,
                "bbox": [x1, y1, x2 - x1, y2 - y1],  # [x, y, width, height]
                "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            })
        
        return results
    
    def visualize_detection(self, image: np.ndarray, results: List[Dict]):
        """可视化检测结果"""
        # 创建图像副本以避免修改原图
        annotated_image = image.copy()
        
        # 绘制检测框和标签
        for result in results:
            x, y, w, h = result["bbox"]
            confidence = result["confidence"]
            cls = result["class"]
            
            # 设置颜色
            # 交通对象的颜色由预定义的COLORS字典决定
            
            # 绘制边界框
            cv2.rectangle(annotated_image, (x, y), (x + w, y + h), color, 2)
            
            # 绘制标签
            label = f"{cls} {confidence:.2f}"
            font = cv2.FONT_HERSHEY_SIMPLEX
            font_scale = 0.5
            thickness = 1
            
            # 获取文本尺寸
            text_size = cv2.getTextSize(label, font, font_scale, thickness)[0]
            
            # 绘制文本背景
            cv2.rectangle(
                annotated_image, 
                (x, y - text_size[1] - 5), 
                (x + text_size[0], y), 
                color, 
                -1
            )
            
            # 绘制文本
            cv2.putText(
                annotated_image, 
                label, 
                (x, y - 5), 
                font, 
                font_scale, 
                (255, 255, 255), 
                thickness
            )
        
        return annotated_image
    
    def update_statistics(self, detection_counts: Dict[str, int]):
        """更新统计信息"""
        # 计算车辆总数和行人数量
        vehicle_classes = ["car", "bicycle", "motorbike", "truck", "bus"]
        vehicle_count = sum(detection_counts.get(cls, 0) for cls in vehicle_classes)
        person_count = detection_counts.get("person", 0)
        total_count = sum(detection_counts.values())
        
        # 更新当前检测统计
        self.vehicle_count_label.setText(f"车辆总数: {vehicle_count}")
        self.person_count_label.setText(f"行人数量: {person_count}")
        
        # 更新总体统计
        for cls, count in detection_counts.items():
            if cls in self.overall_statistics:
                self.overall_statistics[cls] += count
        self.overall_statistics["total"] += total_count
        
        # 更新结果选项卡中的统计信息
        self.stats_summary_label.setText(
            f"总计检测: {self.overall_statistics['total']} | "
            f"车辆: {sum(self.overall_statistics.get(cls, 0) for cls in vehicle_classes)} | "
            f"行人: {self.overall_statistics.get('person', 0)}"
        )
    
    def update_results_table(self, results: List[Dict]):
        """更新结果表格"""
        # 清空表格
        self.results_table.setRowCount(0)
        
        # 添加新结果
        for result in results:
            row_position = self.results_table.rowCount()
            self.results_table.insertRow(row_position)
            
            # 添加数据 - 交通监控相关
            self.results_table.setItem(row_position, 0, QTableWidgetItem(str(result["id"])))
            
            # 交通类别名称映射
            class_map = {
                "car": "小汽车",
                "bicycle": "自行车",
                "motorbike": "摩托车",
                "person": "行人",
                "truck": "卡车",
                "bus": "公交车"
            }
            class_name = class_map.get(result["class"], result["class"])
            self.results_table.setItem(row_position, 1, QTableWidgetItem(class_name))
            
            self.results_table.setItem(row_position, 2, QTableWidgetItem(f"{result['confidence']:.2f}"))
            self.results_table.setItem(row_position, 3, QTableWidgetItem(f"{result['bbox']}"))
            self.results_table.setItem(row_position, 4, QTableWidgetItem(result.get("timestamp", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))))
            
            # 添加操作按钮
            view_btn = QPushButton("查看")
            view_btn.clicked.connect(lambda checked, r=result: self.view_detection_detail(r))
            self.results_table.setCellWidget(row_position, 5, view_btn)
    
    def record_history(self, detection_counts: Dict[str, int]):
        """记录检测历史"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        detection_type = self.current_mode
        
        # 计算车辆总数和行人数量
        vehicle_classes = ["car", "bicycle", "motorbike", "truck", "bus"]
        vehicle_count = sum(detection_counts.get(cls, 0) for cls in vehicle_classes)
        person_count = detection_counts.get("person", 0)
        total_count = sum(detection_counts.values())
        
        # 构建检测结果描述
        detection_summary = []
        for cls, count in detection_counts.items():
            if count > 0:
                class_map = {
                    "car": "小汽车",
                    "bicycle": "自行车",
                    "motorbike": "摩托车",
                    "person": "行人",
                    "truck": "卡车",
                    "bus": "公交车"
                }
                class_name = class_map.get(cls, cls)
                detection_summary.append(f"{class_name}:{count}")
        
        # 添加到历史表格
        row_position = self.history_table.rowCount()
        self.history_table.insertRow(row_position)
        
        self.history_table.setItem(row_position, 0, QTableWidgetItem(timestamp))
        self.history_table.setItem(row_position, 1, QTableWidgetItem(" ".join(detection_summary)))
        self.history_table.setItem(row_position, 2, QTableWidgetItem(str(total_count)))
        self.history_table.setItem(row_position, 3, QTableWidgetItem(str(vehicle_count)))
        self.history_table.setItem(row_position, 4, QTableWidgetItem(str(person_count)))
        
        # 实际项目中这里会保存到数据库或文件
    
    def on_video_frame(self, frame: np.ndarray, results: List[Dict]):
        """处理视频帧检测结果"""
        # 可视化检测结果
        annotated_frame = self.visualize_detection(frame, results)
        
        # 显示结果
        self.display_image(annotated_frame)
        
        # 计算统计信息 - 统计各类别数量
        detection_counts = {}
        for r in results:
            detection_class = r.get("class", "unknown")
            if detection_class in detection_counts:
                detection_counts[detection_class] += 1
            else:
                detection_counts[detection_class] = 1
        
        # 更新统计信息
        self.update_statistics(detection_counts)
        
        # 更新结果表格
        self.update_results_table(results)
    
    def on_video_finished(self):
        """视频处理完成"""
        self.stop_detection()
        QMessageBox.information(self, "完成", "视频处理完成")
    
    def update_confidence(self):
        """更新置信度阈值"""
        confidence = self.confidence_slider.value() / 100.0
        self.confidence_value.setText(f"{confidence:.2f}")
        self.confidence_threshold_label.setText(f"置信度阈值: {confidence:.2f}")
    
    def update_iou(self):
        """更新IOU阈值"""
        iou = self.iou_slider.value() / 100.0
        self.iou_value.setText(f"{iou:.2f}")
    
    def update_device(self):
        """更新计算设备"""
        # 在实际项目中，这里会切换模型的运行设备
        pass
    
    def toggle_custom_path(self):
        """切换自定义保存路径"""
        enabled = self.custom_path_checkbox.isChecked()
        self.save_path_edit.setEnabled(enabled)
        self.browse_path_btn.setEnabled(enabled)
        
        if not enabled:
            self.save_path_edit.setText("")
    
    def select_save_path(self):
        """选择保存路径"""
        path = QFileDialog.getExistingDirectory(self, "选择保存路径")
        if path:
            self.save_path_edit.setText(path)
    
    def get_save_path(self):
        """获取保存路径"""
        if self.custom_path_checkbox.isChecked() and self.save_path_edit.text():
            return self.save_path_edit.text()
        return os.path.join(os.getcwd(), "data", "results")
    
    def view_detection_detail(self, result: Dict):
        """查看检测详情"""
        # 实现查看检测详情的功能
        QMessageBox.information(
            self, 
            "检测详情",
            f"类型: {result['class']}\n"  
            f"置信度: {result['confidence']:.2f}\n"
            f"坐标: {result['bbox']}\n"
            f"时间: {result['timestamp']}"
        )
    
    def export_history(self):
        """导出历史记录"""
        # 实现导出历史记录功能
        QMessageBox.information(self, "导出历史", "历史记录导出功能即将实现")
    
    def clear_history(self):
        """清空历史记录"""
        reply = QMessageBox.question(
            self, 
            "确认清空", 
            "确定要清空所有历史记录吗？此操作不可恢复。",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            self.history_table.setRowCount(0)
            # 实际项目中这里会清空数据库或文件中的记录
    
    def select_model(self):
        """选择模型文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择模型文件", "models", "模型文件 (*.pt)"
        )
        
        if file_path:
            self.model_path_edit.setText(file_path)
    
    def save_settings(self):
        """保存设置"""
        # 实现保存设置功能
        self.statusBar().showMessage("设置已保存")
        QMessageBox.information(self, "保存成功", "设置已成功保存")
    
    def load_settings(self):
        """加载设置"""
        # 实现加载设置功能
        pass
    
    def closeEvent(self, event):
        """窗口关闭事件处理"""
        # 停止检测
        if self.is_detecting:
            self.stop_detection()
        
        # 保存设置
        # self.save_settings()
        
        event.accept()

class VideoProcessor(QThread):
    """视频处理线程"""
    frame_ready = pyqtSignal(np.ndarray, list)
    finished = pyqtSignal()
    
    def __init__(self, video_path=None, camera_id=0):
        super().__init__()
        self.video_path = video_path
        self.camera_id = camera_id
        self.running = False
    
    def run(self):
        """线程运行函数"""
        self.running = True
        
        try:
            # 打开视频或摄像头
            cap = cv2.VideoCapture(self.video_path if self.video_path else self.camera_id)
            
            if not cap.isOpened():
                raise Exception("无法打开视频或摄像头")
            
            # 处理视频帧
            while self.running:
                ret, frame = cap.read()
                if not ret:
                    break
                
                # 模拟检测结果
                results = self.simulate_detection_results(frame)
                
                # 发送处理后的帧和结果
                self.frame_ready.emit(frame, results)
                
                # 控制处理速度
                QThread.msleep(33)  # 约30 FPS
            
            cap.release()
            
        except Exception as e:
            logger.error(f"视频处理错误: {e}")
        
        self.finished.emit()
    
    def stop(self):
        """停止视频处理"""
        self.running = False
    
    def simulate_detection_results(self, frame: np.ndarray):
        """模拟交通场景检测结果"""
        import random
        height, width = frame.shape[:2]
        results = []
        
        # 交通场景相关类别及其配置
        traffic_classes = {
            'person': {'count': (1, 3), 'width': (40, 80), 'height': (80, 150), 'confidence': (0.7, 0.95)},
            'car': {'count': (1, 2), 'width': (80, 150), 'height': (60, 100), 'confidence': (0.75, 0.99)},
            'bicycle': {'count': (0, 2), 'width': (60, 120), 'height': (50, 90), 'confidence': (0.7, 0.9)},  
            'motorbike': {'count': (0, 2), 'width': (60, 100), 'height': (50, 80), 'confidence': (0.7, 0.9)},
            'truck': {'count': (0, 1), 'width': (100, 200), 'height': (70, 120), 'confidence': (0.8, 0.99)},
            'bus': {'count': (0, 1), 'width': (120, 200), 'height': (80, 130), 'confidence': (0.8, 0.99)}
        }
        
        # 为每个类别生成检测结果
        for class_name, config in traffic_classes.items():
            # 随机决定该类别是否出现
            if random.random() > 0.3:  # 70%概率出现该类别
                # 生成该类别的检测数量
                count = random.randint(config['count'][0], config['count'][1])
                
                for _ in range(count):
                    # 生成边界框
                    box_width = random.randint(config['width'][0], config['width'][1])
                    box_height = random.randint(config['height'][0], config['height'][1])
                    
                    x1 = random.randint(50, width - box_width - 50)
                    y1 = random.randint(50, height - box_height - 50)
                    x2 = x1 + box_width
                    y2 = y1 + box_height
                    
                    # 生成置信度
                    confidence = random.uniform(config['confidence'][0], config['confidence'][1])
                    
                    results.append({
                        'x1': x1,
                        'y1': y1,
                        'x2': x2,
                        'y2': y2,
                        'class_name': class_name,
                        'confidence': confidence
                    })
        
        return results

# 主入口点已在文件上方定义